﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Collections;
using System.Runtime.Serialization;

namespace GtsServer.Service.Index.DAL
{
    public class ConcurrentHashSet<T> : ISerializable, IDeserializationCallback,  ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable
    {
        private readonly HashSet<T> underlyingHashSet = new HashSet<T>();
        private readonly object syncRoot = new object();
        private readonly ConcurrentQueue<T> underlyingQueue;
        private bool requiresSync;
        private bool isDirty;

        public ConcurrentHashSet()
        {
            underlyingQueue = new ConcurrentQueue<T>();
        }

        public ConcurrentHashSet(IEnumerable<T> items)
        {
            underlyingQueue = new ConcurrentQueue<T>(items);
        }

        private void UpdateLists()
        {
            if (!isDirty)
                return;
            lock (syncRoot)
            {
                requiresSync = true;
                T temp;
                while (underlyingQueue.TryDequeue(out temp))
                    underlyingHashSet.Add(temp);
                requiresSync = false;
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            lock (syncRoot)
            {
                UpdateLists();
                return underlyingHashSet.GetEnumerator();
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void Add(T item)
        {
            if (requiresSync)
                lock (syncRoot)
                    underlyingQueue.Enqueue(item);
            else
                underlyingQueue.Enqueue(item);
            isDirty = true;
        }

        public bool Add(object value)
        {
            if (requiresSync)
                lock (syncRoot)
                    underlyingQueue.Enqueue((T)value);
            else
                underlyingQueue.Enqueue((T)value);
            isDirty = true;
            lock (syncRoot)
            {
                if (underlyingHashSet.Contains((T)value))
                {
                    return false;
                }
                else
                {
                    UpdateLists();
                    return true;
                }
                //return underlyingHashSet.IndexOf((T)value);
            }
        }

        //public bool Contains(object value)
        //{
        //    lock (syncRoot)
        //    {
        //        UpdateLists();
        //        return underlyingHashSet.Contains((T)value);
        //    }
        //}

        //public int IndexOf(object value)
        //{
        //    lock (syncRoot)
        //    {
        //        UpdateLists();
        //        return underlyingHashSet.IndexOf((T)value);
        //    }
        //}

        //public void Insert(int index, object value)
        //{
        //    lock (syncRoot)
        //    {
        //        UpdateLists();
        //        underlyingHashSet.Insert(index, (T)value);
        //    }
        //}

        //public void Remove(object value)
        //{
        //    lock (syncRoot)
        //    {
        //        UpdateLists();
        //        underlyingHashSet.Remove((T)value);
        //    }
        //}

        //public void RemoveAt(int index)
        //{
        //    lock (syncRoot)
        //    {
        //        UpdateLists();
        //        underlyingHashSet.RemoveAt(index);
        //    }
        //}

        //T IList<T>.this[int index]
        //{
        //    get
        //    {
        //        lock (syncRoot)
        //        {
        //            UpdateLists();
        //            return underlyingHashSet[index];
        //        }
        //    }
        //    set
        //    {
        //        lock (syncRoot)
        //        {
        //            UpdateLists();
        //            underlyingHashSet[index] = value;
        //        }
        //    }
        //}

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool IsFixedSize
        {
            get { return false; }
        }

        public void Clear()
        {
            lock (syncRoot)
            {
                UpdateLists();
                underlyingHashSet.Clear();
            }
        }

        public bool Contains(T item)
        {
            lock (syncRoot)
            {
                UpdateLists();
                return underlyingHashSet.Contains(item);
            }
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            lock (syncRoot)
            {
                UpdateLists();
                underlyingHashSet.CopyTo(array, arrayIndex);
            }
        }

        public bool Remove(T item)
        {
            lock (syncRoot)
            {
                UpdateLists();
                return underlyingHashSet.Remove(item);
            }
        }

        public void CopyTo(Array array, int index)
        {
            lock (syncRoot)
            {
                UpdateLists();
                underlyingHashSet.CopyTo((T[])array, index);
            }
        }

        public int Count
        {
            get
            {
                lock (syncRoot)
                {
                    UpdateLists();
                    return underlyingHashSet.Count;
                }
            }
        }

        public object SyncRoot
        {
            get { return syncRoot; }
        }

        public bool IsSynchronized
        {
            get { return true; }
        }

        //public int IndexOf(T item)
        //{
        //    lock (syncRoot)
        //    {
        //        UpdateLists();
        //        return underlyingHashSet.IndexOf(item);
        //    }
        //}

        //public void Insert(int index, T item)
        //{
        //    lock (syncRoot)
        //    {
        //        UpdateLists();
        //        underlyingHashSet.Insert(index, item);
        //    }
        //}

        bool ISet<T>.Add(T item)
        {
            throw new NotImplementedException();
        }

        public void ExceptWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public void IntersectWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public bool IsProperSubsetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public bool IsProperSupersetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public bool IsSubsetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public bool IsSupersetOf(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public bool Overlaps(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public bool SetEquals(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public void SymmetricExceptWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public void UnionWith(IEnumerable<T> other)
        {
            throw new NotImplementedException();
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            throw new NotImplementedException();
        }

        public void OnDeserialization(object sender)
        {
            throw new NotImplementedException();
        }
    }
}
